package com.irs.irsforum.service.impl;

import com.alibaba.rocketmq.shade.com.alibaba.fastjson.JSONArray;
import com.alibaba.rocketmq.shade.com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.irs.irsforum.entity.Comment;
import com.irs.irsforum.entity.IndexPage;
import com.irs.irsforum.entity.IndexPost;
import com.irs.irsforum.entity.Post;
import com.irs.irsforum.entity.Resources;
import com.irs.irsforum.mapper.BehaviorMapper;
import com.irs.irsforum.mapper.CommentMapper;
import com.irs.irsforum.mapper.FavoriteMapper;
import com.irs.irsforum.mapper.PostMapper;
import com.irs.irsforum.mapper.SubjectMapper;
import com.irs.irsforum.mapper.UserMapper;
import com.irs.irsforum.service.IPostService;
import com.irs.irsforum.utils.RecommendAlgorithm;
import com.irs.irsforum.utils.TimeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yihuili
 * @since 2020-01-18
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements IPostService {
    private static final Logger logger =
            LoggerFactory.getLogger(PostServiceImpl.class);

    @Autowired
    PostMapper postMapper;
    @Autowired
    CommentMapper commentMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    SubjectMapper subjectMapper;
    @Autowired
    FavoriteMapper favoriteMapper;
    @Autowired
    BehaviorMapper behaviorMapper;
    @Autowired
    RedisTemplate redisTemplate;

    /**首页推荐： 前10条为推荐帖子，根据行为记录的时间以及行为等级进行收集，率先推荐behavior=0并且时间较近的帖子10条，
        不足再推荐behavior=1并且时间较近的帖子，直到凑满10条为止。
       1.通过userId查找behavior中bahaviorType=1的用户，即定义为显性行为的用户所联系的帖子Id即dominancePostId。
       2.通过这些dominancePostId找到这一类的subjectId，即dominanceSubjectId。
       3.再通过dominanceSubjectId找到10条Post。
       4.若不足10条，则在进行隐性行为的查找，方式同上。
       5.再找到其他帖子凑齐10条为止。
    */
    @Override
    public List<IndexPost> showPostByPage(Integer currentPage, Integer pageSize, Long userId) {
        if (pageSize < Resources.getPageSize()) {
            logger.error("pageSize ={}，小于等于0", pageSize);
            pageSize = Resources.getPageSize();
        }
        int start = (currentPage - 1) * pageSize;
        /*最终返回的post列表*/
        List<IndexPost> postList;
        /*推荐Post列表*/
        List<Long> postIdList;
        /*当前找到的推荐长度*/
        Integer length = 0;
        postList = JSONArray.parseArray((String) redisTemplate.opsForValue().get("RECOMMONDPOST-USER:" + userId), IndexPost.class);
        if (postList == null) {
            postList = new ArrayList<>();
            if (currentPage == 1) {
                /*首页推荐算法*/
                length = RecommendAlgorithm.indexRecommend(userId, postList);
            }
            if (postList != null && postList.size() > 0) {
                logger.info("开始将推荐post以recommondPost-user:userId,value的形式存入redis ");
                redisTemplate.opsForValue().set("RECOMMONDPOST-USER:" + userId, JSONArray.toJSONString(postList), Resources.getCacheTime(), Resources.getRedisTimeType());
                logger.info("开始将其他帖子位置存入redis ");
                redisTemplate.opsForValue().set("PAGE-START:" + userId, length, Resources.getCacheTime(), Resources.getRedisTimeType());
            }
            logger.info("<----------------------结束首页帖子推荐");
        } else {
            logger.info("发现首页帖子缓存，开始查找其他帖子位置--------------->");
            Integer value = (Integer) redisTemplate.opsForValue().get("PAGE-START:" + userId);
            if (value != null && start != 0) {
                start = start - value;
            }
            logger.info("其他帖子位置为: ={}", start);
            logger.info("<---------------结束查找其他帖子位置");
        }
        postIdList = postList.stream().map(IndexPost::getId).collect(Collectors.toList());
        if (currentPage != 1) {
            postList.clear();
        }
        postList.addAll(postMapper.showPostByPage(new IndexPage(start, pageSize - postList.size(), null, null, postIdList, userId)));
        setIsSender(postList, userId);
        return postList;
    }

    private void setIsSender(List<IndexPost> postList, Long userId) {
        postList.stream().forEach(e -> e.setIsSender(e.getUserId().equals(userId) ? 1 : 0));
    }

    @Override
    public JSONObject getTotalPostNum(Integer pageSize) {
        if (pageSize < Resources.getPageSize()) {
            logger.error("pageSize ={}，小于等于0", pageSize);
            pageSize = Resources.getPageSize();
        }
        int totalNum = postMapper.getTotalNum();
        int page = (totalNum + pageSize - 1) / pageSize;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("totalNum", totalNum);
        jsonObject.put("page", page);
        return jsonObject;
    }

    @Override
    public Post showPost(Long postId, Long userId) {
        Post post = postMapper.showPost(postId, userId);
        if (post == null) {
            logger.error("post 为空");
            return null;
        }
        if (post.getReplyNum() > 0) {
            List<Comment> commentList = commentMapper.getCommentListByPostId(postId);
            commentList.stream().forEach(comment -> comment.setUserNickName(userMapper.getUserById(comment.getUserId()) == null ? null : userMapper.getUserById(comment.getUserId()).getNickName()));
            commentList.stream().forEach(e -> e.setIsSender(e.getUserId().equals(userId) ? 1 : 0));
            post.setCommentList(commentList);
        }
        if (post.getUserId().equals(userId)) {
            post.setIsSender(1);
        }

        return post;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer writePost(Post post) throws SQLException {
        post.setCreationTime(TimeUtil.getSqlTime());
        Integer result;
        try {
            result = postMapper.writePost(post);
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new SQLException("插入异常");
        }
        return result;
    }

    @Override
    public List<IndexPost> getPostByUserId(Long userId) {
        List<IndexPost> postList = postMapper.getPostByUserId(userId);
        postList.forEach(e -> e.setIsSender(1));
        return postList;
    }

    @Override
    public List<IndexPost> getFavoriteByUserId(Long userId) {
        List<IndexPost> favoriteList = postMapper.getFavoriteByUserId(userId);
        setIsSender(favoriteList, userId);
        return favoriteList;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateCommentNum(Long postId, Long number) {
        Integer result = postMapper.updateCommentNum(postId, number);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateFavoriteNum(Long postId, Long number) {
        Integer result = postMapper.updateFavoriteNum(postId, number);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer delPost(Long postId, Long userId) {
        Integer existPost = postMapper.isExistPost(postId, userId);
        Integer result = 0;
        if (existPost != null && existPost != 0) {
            result = postMapper.updateIsExist((long) 0, postId);
        }
        return result;
    }

}
